package com.zp.self.module.level_5_设计模式.创建型模式.Ⅰ_单例模式.懒汉;

/**
 * @author ZengPeng
 * @Description 这种方式采用双锁机制，安全且在多线程情况下能保持高性能。 【推荐】
 * @date 2020/4/26
 **/
public class Singleton_双重检查 {
    private Singleton_双重检查() {
    }

    /**
     * Description: 不加volatile 代码：singleton = new Singleton_双重检查() 可能发生指令重排，如下：

     正常情况：
          memory = allocate();    //1：分配对象的内存空间
          initInstance(memory);   //2：初始化对象
          instance = memory;      //3：设置instance指向刚分配的内存地址

     指令重排：
          memory = allocate();    //1：分配对象的内存空间
          instance = memory;      //3：设置instance指向刚分配的内存地址（此时对象还未初始化）
          ctorInstance(memory);   //2：初始化对象

     当只进行了步骤【1、3】只创建到一半时，再来一个线程获取单例对象 就返回了半个对象，这时半个对象操作可能会异常。
     如果对象初始化很久 那这种情况更容易出现
     */
    private volatile static Singleton_双重检查 instance;

    /**
     * Description: Singleton_双重检查
     */
    public static Singleton_双重检查 getInstance() {
        if (instance == null) {
            synchronized (Singleton_双重检查.class) {
                if (instance == null)
                    instance = new Singleton_双重检查();
            }
        }
        return instance;
    }

    //用完清理，防止占用内存。不知是否可取 ？ 多线程下可能报错空指针 。
    //应该在两个静态方法上加Singleton_双重检查串行化处理，保证线程安全，但效率低
    public  static void clear(){
        instance = null;
    }

    public static void main(String[] args) {
        Singleton_双重检查 instance = Singleton_双重检查.getInstance();

    }
}